#include "StepByStep.h"

int yyparse(void);

extern FILE *yyin;

int GetObjectIndex(char Name[])
{
  TypedList *Pt;
  int        i;

  Pt = Objects;
  for (i = 0; i < NumObject; i++, Pt++)
    if (IsSame(Name, Pt->VList.Name)) return i;

  return NOFOUND;
}

char* GetObjectName(int idx)
{
  if (IsConstant(idx)) return (Constants+idx-CONSTANT)->VList.Name;
  
  return (Objects+idx)->VList.Name;
}

StringList* GetObjectType(int idx)
{
  if (IsConstant(idx)) return (Constants+idx-CONSTANT)->Type;

  return (Objects+idx)->Type;
}

// Instantiate Forall Goal Node
void InstantiateForallNode(PENode *pt, char *theVariable, char *theConstant, int ParaIdx)
{
/*TokenList *tmp, *thePred, *thePara, *ParaList, *end;
  PENode    *List, *prior, *np;
  
  prior = NULL;
  List = pt->sons;
  while (List != NULL) {
    if (List->Type == NOT) thePred = List->sons->Pred;  // NOT node
    else thePred = List->Pred;  // ATOM node
    ParaList = thePred->next;
    
    while (ParaList != NULL) {
      if (strcmp(ParaList->VList.Value, theVariable) == SAME) {
        // New node
        if (List->Type == ATOM) np = NewPENode(ATOM);
        else if (List->Type == NOT) {
                np = NewPENode(NOT);
                np->sons = NewPENode(ATOM);
             }

        // Link relationship
        np->next = List;
        if (prior == NULL) pt->sons = np;
        else prior->next = np;
        prior = np;

        if (List->Type == NOT) np = np->sons;

        // predicate
        np->Pred = tmp = (TokenList *) calloc(1, sizeof(TokenList));
        strcpy(tmp->VList.Value, thePred->VList.Value);
        tmp->ParaIdx = thePred->ParaIdx;
        end = tmp;

        // parameters
        thePara = thePred->next;
        while (thePara != NULL) {
          tmp = (TokenList *) calloc(1, sizeof(TokenList));
          if (strcmp(thePara->VList.Value, theVariable) == SAME) {
             strcpy(tmp->VList.Value, theConstant);
             tmp->ParaIdx = ParaIdx;
          }
          else {
                 strcpy(tmp->VList.Value, thePara->VList.Value);
                 tmp->ParaIdx = thePara->ParaIdx;
          }
          tmp->next = end->next;
          end->next = tmp;
          end = tmp;
          thePara = thePara->next;
        }

        break;
      }  // if SAME
      
      ParaList = ParaList->next;
    }
    prior = List;
    List = List->next;
  }*/
}

void InstanForallNodes(PENode *pt, TypedList *theInsList, int NumInsList, char *varName, char *typeName)
{
  int i;
  
  for (i = 0; i < NumInsList; i++,theInsList++)
    if (IsSame(typeName, theInsList->Type->Name))
       InstantiateForallNode(pt, varName, theInsList->VList.Name, i);
}

void DelFromForallList(PENode *pt, char *varName)
{
  TokenList *thePara;
  PENode    *prior, *List, *tmp;
  Bool       found;

  prior = NULL;
  List = pt->sons;
  while (List != NULL) {
    if (List->Type == NOT) thePara = List->sons->Pred->next;
    else thePara = List->Pred->next;
    
    found = FALSE;
    while (thePara != NULL) {
      if (IsSame(thePara->VList.Name, varName)) {
          found = TRUE;
          break;
        }
      thePara = thePara->next;
    }
    
    if (found) {
        tmp = List;
        List = List->next;
        if (prior == NULL) pt->sons = List;
        else prior->next = List;
        if (tmp->sons != NULL) free(tmp->sons);
        free(tmp);
    }
    else {
           prior = List;
           List = List->next;
    }
  }
}

void ParseForallGoalNode(PENode *PE)
{
  TypedList  *theVars;
  StringList *theType;
  char       *typeName;

  theVars = PE->Vars;        // Variables
  theType = theVars->Type; 
  if (PE->sons->Type == AND) PE = PE->sons;  // more than one predicate
  
  while (theVars != NULL) {
    typeName = theType->Name;
    InstanForallNodes(PE, Objects, NumObject, theVars->VList.Name, typeName);
    InstanForallNodes(PE, Constants, NumConstant, theVars->VList.Name, typeName);
    
    // Get Next Type
    if (theType->next != NULL) theType = theType->next;
    else {
           DelFromForallList(PE, theVars->VList.Name);
           theVars = theVars->next;
           if (theVars != NULL) theType = theVars->Type;
    }
   }  // while
}

/* read PDDL and establish original structure */
void GetFactInfo(char *Filename)
{
  FILE *File;

  File = fopen(Filename, "r");
  if (File == NULL) {
     fprintf(Output,"No Fact File: %s\n", Filename);
     exit(ERROR);
  }

  lineno = 1;
  yyin = File;
  yyparse();
  fclose(File);
}

void HandleForallGoalNode()
{
  PENode *PE1, *PE2, *PE3, *PE4;

  PE1 = Goal;
  while (PE1 != NULL) {
    switch (PE1->Type) {
      case FORALL:
           ParseForallGoalNode(PE1);
           // free FORALL node
           PE3 = PE1;
           PE1 = PE1->next;

           PE4 = PE3;  PE3 = PE3->sons;  free(PE4);

           if (PE3->Type == AND) { // if having AND node, free it
              PE4 = PE3; PE3 = PE3->sons; free(PE4);
           }

           if (PE2 == NULL) Goal->sons = PE3;
           else PE2->next = PE3;

           while (PE3 != NULL) { PE2 = PE3;  PE3 = PE3->next; }
           PE2->next = PE1;
           break;
//   case EXIST: break;
//   case IMPLY: break;
     default:
           break;
    }
    PE2 = PE1;  PE1 = PE1->next;
  }
}

void TransPredInfo(TokenList *Pred)
{
  int idx;

  idx = GetPredIndex(Pred->VList.Name);
  if (idx == NOFOUND) {
     fprintf(Output, "Invalid Predication: %s\n", Pred->VList.Name);
     exit(ERROR);
  }
  Pred->VList.ParaIdx = idx;

  for (Pred = Pred->next; Pred != NULL; Pred = Pred->next) {
    idx = GetObjectIndex(Pred->VList.Name);
    if (idx == NOFOUND) idx = GetConstantIndex(Pred->VList.Name);

    if (idx == NOFOUND) {
       fprintf(Output, "Invalid Fact in Predication: %s\n", Pred->VList.Name);
       exit(ERROR);
    }

    Pred->VList.ParaIdx = NOFOUND;
    InsertOneValueIntoValueList(idx, &(Pred->VList));
  }
}

void TransFactInfo()
{
  StateOfPlan *FT;
  StringList  *Pt;
  TypedList   *Pt1, *Pt2, *Pt3;
  PredFact    *FT1;
  PENode      *PE, *PE1;

  if (!IsSame(DomName, Name)) {
     fprintf(Output,"\n\7The fact is not the fact of domain(%s).\n\n", Name);
     exit(ERROR);
  }

  Pt1 = Objects;
  while (Pt1 != NULL) {
    Pt3 = Pt1->next;

    if (Pt3 == NULL) break;

    for (Pt2 = Objects; Pt2 != Pt3; Pt2 = Pt2->next)
      if (IsSame(Pt2->VList.Name, Pt3->VList.Name)) {
         Pt = (StringList *) calloc(1, sizeof(StringList));
         strcpy(Pt->Name, Pt3->Type->Name);
         Pt->next = Pt2->Type;
         Pt2->Type = Pt;
         Pt1->next = Pt3->next;   free(Pt3);
         break;
      }

    if (Pt2 == Pt3) Pt1 = Pt1->next;
  }

  Objects = TransTypedListToArray(Objects, &NumObject);

  for (PE = Init; PE != NULL; PE = PE->next) TransPredInfo(PE->Pred);

  NumTarget = 0;
  for (PE = Goal; PE != NULL; NumTarget++,PE=PE->next)
    TransPredInfo(PE->Pred);

  if (Universal) HandleForallGoalNode();

#ifdef DISPLAYTREE1
  PrintFactInformation(); // Print original structure info
#endif

  State = (StateOfPlan *) calloc(NumPred, sizeof(StateOfPlan));
  for (PE = Init; PE != NULL; PE = PE1) {
    PE1 = PE->next;
    if (PE->Type == NOT) FreeTokenList(PE->Pred);
    else {
           FT = State + PE->Pred->VList.ParaIdx;

           FT1 = (PredFact *) calloc(1, sizeof(PredFact));
           FT1->Para = PE->Pred->next;

           FT->Left++;
           FT->Total++;
           FT1->next = FT->List;  FT->List = FT1;
    }

    free(PE);
  }
}
